package com.example.lib_core.task

import io.reactivex.Maybe
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject

open class ProgressTask<PROGRESS, RESULT> : ITask {
    private var progressPublishSubject: PublishSubject<PROGRESS>? = null
    private var progressDisposable: Disposable? = null
    private var disposable: Disposable? = null

    private var isSuccess: Boolean = false
    private var isCancelled: Boolean = false
    private var running = false
    private var hasError = false

    private var progressAction: ((PROGRESS) -> Unit)? = null
    private var successAction: ((RESULT) -> Unit)? = null
    private var errorAction: ((Throwable) -> Unit)? = null
    private var beforeAction: (() -> Unit)? = null
    private var interruptedAction: (() -> Unit)? = null

    val isRunning: Boolean
        get() = disposable != null && !disposable!!.isDisposed && running && !isCancelled

    /**
     * 启动任务
     */
    open fun start(): ProgressTask<PROGRESS, RESULT> {
        if (isRunning)
            throw IllegalStateException("already started")

        val current = this
        isSuccess = false
        isCancelled = false
        hasError = false
        running = true

        val subject = PublishSubject.create<PROGRESS>()
        progressPublishSubject = subject
        progressDisposable = subject
            .observeOn(if (Task.ANDROID_PLATFORM) AndroidSchedulers.mainThread() else Schedulers.single())
            .subscribe(
                // PROGRESS
                { progress ->
                    current.onTaskProgress(progress)
                    progressAction?.invoke(progress)
                },
                { error -> error.printStackTrace() })

        // BEFORE
        current.onTaskBefore()
        beforeAction?.invoke()

        disposable = Maybe.create<RESULT> { emitter ->
            try {
                val result = onTaskRun()
                emitter.onSuccess(result)
            } catch (e: Exception) {
                if (!isCancelled)
                    emitter.onError(e)
            }
        }.subscribeOn(Schedulers.newThread())
            .observeOn(if (Task.ANDROID_PLATFORM) AndroidSchedulers.mainThread() else Schedulers.single())
            .unsubscribeOn(if (Task.ANDROID_PLATFORM) AndroidSchedulers.mainThread() else Schedulers.single())
            .doOnDispose {

                // CANCEL
                if (!isSuccess && !hasError) {
                    Single.just(isCancelled)
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe { isCancelled ->
                            if (isCancelled) {
                                onTaskInterrupted()
                                interruptedAction?.invoke()
                            }
                        }
                }
            }
            .subscribe(
                // SUCCESS
                { result ->
                    if (!isCancelled) {
                        running = false
                        isSuccess = true
                        current.onTaskSuccess(result)
                        successAction?.invoke(result)
                    }
                },
                // ERROR
                { throwable ->
                    if (!isCancelled) {
                        running = false
                        isSuccess = false
                        hasError = true
                        current.onTaskError(throwable)
                        errorAction?.invoke(throwable)
                    }
                })

        return this
    }

    /**
     * 主动中断任务
     */
    open fun cancel() {
        isCancelled = true
        progressDisposable?.dispose()
        disposable?.dispose()
    }

    /**
     * 发送进度
     */
    fun publishProgress(progress: PROGRESS) {
        progressPublishSubject?.onNext(progress)
    }

    /**
     * 事件：任务执行前
     */
    fun before(action: () -> Unit): ProgressTask<PROGRESS, RESULT> {
        beforeAction = action
        return this
    }

    /**
     * 事件：进度
     */
    fun progress(action: (PROGRESS) -> Unit): ProgressTask<PROGRESS, RESULT> {
        progressAction = action
        return this
    }

    /**
     * 事件：任务成功
     */
    fun success(action: (RESULT) -> Unit): ProgressTask<PROGRESS, RESULT> {
        successAction = action
        return this
    }

    /**
     * 事件：任务出错
     */
    fun error(action: (Throwable) -> Unit): ProgressTask<PROGRESS, RESULT> {
        errorAction = action
        return this
    }

    /**
     * 事件：任务主动中断
     */
    fun interrupted(action: () -> Unit): ProgressTask<PROGRESS, RESULT> {
        interruptedAction = action
        return this
    }

    open fun onTaskBefore() {}

    @Throws(Exception::class)
    protected open fun onTaskRun(): RESULT {
        throw NotImplementedError()
    }

    open fun onTaskProgress(progress: PROGRESS) {}

    open fun onTaskSuccess(result: RESULT) {}

    open fun onTaskError(error: Throwable) {}

    open fun onTaskInterrupted() {}

    private var proxy = object : ITaskProxy {
        override fun start() {
            this@ProgressTask.start()
        }

        override fun stop() {
            this@ProgressTask.cancel()
        }
    }

    override fun getProxy(): ITaskProxy {
        return proxy
    }

}